package info.motteke.swt;

import java.util.Timer;
import java.util.TimerTask;

import org.eclipse.swt.SWT;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.Device;
import org.eclipse.swt.graphics.GC;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.ImageLoader;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.graphics.TextLayout;
import org.eclipse.swt.widgets.Display;

public class AnimationEntry extends ReplaceEntry {

    private final LayoutText text;

    private volatile int index = 1;

    private Image[] images;

    private int[] waits;

    private final int width;

    private final int height;

    private final Timer timer;

    public AnimationEntry(LayoutText text, TextLayout layout, Point margin, int offset, ImageLoader loader, Timer timer) {
        super(layout, margin, offset);
        this.timer = timer;
        this.text = text;
        width = loader.logicalScreenWidth;
        height = loader.logicalScreenHeight;

        createImages(loader);
        timer.schedule(new AnimationTimer(this, text), 0);
    }

    private void createImages(ImageLoader loader) {
        ImageData[] data = loader.data;

        int length = data.length;
        images = new Image[length];
        waits = new int[length];

        Device device = text.getDisplay();

        final int background = loader.backgroundPixel;
        int transition = SWT.DM_FILL_BACKGROUND;

        for (int i = 0; i < length; i++) {
            ImageData id = data[i];

            // 画像のベース作成
            Image image = new Image(device, width, height);

            // 背景色
            Color bg = new Color(device, id.palette.colors[background]);

            // 画像処理用のGC作成
            GC gc = new GC(image);
            gc.setBackground(bg);

            switch (transition) {
                case SWT.DM_FILL_NONE:
                    /* FALLTHROUGH */
                case SWT.DM_UNSPECIFIED:
                    /* FALLTHROUGH */
                case SWT.DM_FILL_PREVIOUS:
                    gc.drawImage(images[i - 1], 0, 0);
                    break;
            }

            drawImage(gc, id);
            images[i] = image;
            waits[i] = id.delayTime * 10;

            bg.dispose();
            gc.dispose();
            transition = id.disposalMethod;
        }
    }

    private void drawImage(GC gc, ImageData imageData) {
        Image image = new Image(text.getDisplay(), imageData);

        int width = imageData.width;
        int height = imageData.height;
        int x = imageData.x;
        int y = imageData.y;

        gc.drawImage(image, 0, 0, width, height, x, y, width, height);
        image.dispose();
    }

    public int getWidth() {
        return width;
    }

    public int getHeight() {
        return height;
    }

    private synchronized void nextImage() {
        index = (index + 1) % images.length;
    }

    private Image getImage() {
        return images[index];
    }

    private int getWait() {
        return waits[index];
    }

    @Override
    protected void draw(GC gc) {
        Point p = getDrawLocation();
        gc.drawImage(getImage(), p.x, p.y);
    }

    @Override
    protected void dispose() {
        for (Image image : images) {
            image.dispose();
        }
    }

    private static class AnimationTimer extends TimerTask {

        private final AnimationEntry entry;

        private final LayoutText text;

        private AnimationTimer(AnimationEntry entry, LayoutText text) {
            this.entry = entry;
            this.text = text;
        }

        @Override
        public void run() {
            Display display = text.getDisplay();

            display.asyncExec(new Runnable(){
                @Override
                public void run() {
                    text.redraw();
                }
            });

            entry.nextImage();
            entry.timer.schedule(new AnimationTimer(entry, text), entry.getWait());
        }
    }
}
